package cn.ieclipse.pay.alipay;

import android.text.TextUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;

import static cn.ieclipse.pay.alipay.Alipay.isRSA2;

public class OrderInfoUtil2_0 {
    
    /**
     * 构造授权参数列表
     *
     * @param pid
     * @param app_id
     * @param target_id
     *
     * @return
     */
    public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
        Map<String, String> keyValues = new HashMap<String, String>();
        
        // 商户签约拿到的app_id，如：2013081700024223
        keyValues.put("app_id", app_id);
        
        // 商户签约拿到的pid，如：2088102123816631
        keyValues.put("pid", pid);
        
        // 服务接口名称， 固定值
        keyValues.put("apiname", "com.alipay.account.auth");
        
        // 商户类型标识， 固定值
        keyValues.put("app_name", "mc");
        
        // 业务类型， 固定值
        keyValues.put("biz_type", "openservice");
        
        // 产品码， 固定值
        keyValues.put("product_id", "APP_FAST_LOGIN");
        
        // 授权范围， 固定值
        keyValues.put("scope", "kuaijie");
        
        // 商户唯一标识，如：kkkkk091125
        keyValues.put("target_id", target_id);
        
        // 授权类型， 固定值
        keyValues.put("auth_type", "AUTHACCOUNT");
        
        // 签名类型
        keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
        
        return keyValues;
    }
    
    /**
     * 构造支付订单参数列表
     * 详情参数请参考
     * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.IXhv9U&treeId=193&articleId=105465&docType=1
     *
     * @return
     */
    public static Map<String, String> buildOrderParamMap(String out_trade_no, String subject, String body, String fee,
                                                         String notify_url) {
        Map<String, String> keyValues = new HashMap<String, String>();
        
        keyValues.put("app_id", Alipay.Config.appId);
        
        keyValues.put("biz_content",
            "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + fee + "\","
                + "\"subject\":\"" + subject + "\",\"body\":\"" + body + "\",\"out_trade_no\":\"" + out_trade_no
                + "\"}");
        
        keyValues.put("charset", "utf-8");
        
        keyValues.put("method", "alipay.trade.app.pay");
        
        keyValues.put("sign_type", isRSA2() ? "RSA2" : "RSA");
        
        keyValues.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
        
        keyValues.put("version", "1.0");
        
        keyValues.put("notify_url", TextUtils.isEmpty(notify_url) ? Alipay.Config.notify_url : notify_url);
        
        return keyValues;
    }
    
    /**
     * 构造支付订单参数信息
     *
     * @param map 支付订单参数
     *
     * @return
     */
    public static String buildOrderParam(Map<String, String> map) {
        List<String> keys = new ArrayList<String>(map.keySet());
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            sb.append(buildKeyValue(key, value, true));
            sb.append("&");
        }
        
        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        sb.append(buildKeyValue(tailKey, tailValue, true));
        
        return sb.toString();
    }
    
    /**
     * 拼接键值对
     *
     * @param key
     * @param value
     * @param isEncode
     *
     * @return
     */
    private static String buildKeyValue(String key, String value, boolean isEncode) {
        StringBuilder sb = new StringBuilder();
        sb.append(key);
        sb.append("=");
        if (isEncode) {
            try {
                sb.append(URLEncoder.encode(value, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                sb.append(value);
            }
        }
        else {
            sb.append(value);
        }
        return sb.toString();
    }
    
    /**
     * 对支付参数信息进行签名
     *
     * @param map 待签名授权信息
     *
     * @return
     */
    public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
        List<String> keys = new ArrayList<String>(map.keySet());
        // key排序
        Collections.sort(keys);
        
        StringBuilder authInfo = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            authInfo.append(buildKeyValue(key, value, false));
            authInfo.append("&");
        }
        
        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        authInfo.append(buildKeyValue(tailKey, tailValue, false));
        
        String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
        String encodedSign = ""; // 如果签名失败，设置签名为空
        if (oriSign != null) {
            try {
                encodedSign = URLEncoder.encode(oriSign, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return "sign=" + encodedSign;
    }
    
    /**
     * 要求外部订单号必须唯一。
     *
     * @return
     */
    public static String genOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
        Date date = new Date();
        String key = format.format(date);
        
        Random r = new Random();
        key = key + r.nextInt();
        key = key.substring(0, 15);
        return key;
    }
    
    public static String getOrderInfo(Map<String, String> params) {
        boolean rsa2 = Alipay.isRSA2();
        String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
        
        String privateKey = rsa2 ? Alipay.Config.rsa2_private : Alipay.Config.rsa_private;
        String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);
        final String orderInfo = orderParam + "&" + sign;
        return orderInfo;
    }
}
